package it.polimi.swimv2.session;

import it.polimi.swimv2.entities.Ability;
import it.polimi.swimv2.entities.HelpRequest;
import it.polimi.swimv2.entities.Message;
import it.polimi.swimv2.entities.RequestStatus;
import it.polimi.swimv2.entities.User;
import it.polimi.swimv2.exception.HelpRequestException;
import it.polimi.swimv2.remote.HelpRequestManagerRemote;

import java.util.Collection;
import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import javax.persistence.Query;

/**
 * Session Bean implementation class HelpRequestManager
 */
@Stateless
public class HelpRequestManager implements HelpRequestManagerRemote, HelpRequestManagerLocal {
	
	@PersistenceContext(unitName = "swimv2")
	EntityManager em;

	/**
	 * Default constructor.
	 */
	public HelpRequestManager() {

	}

	
	@Override
	public Collection<HelpRequest> getReceivedHelpRequest(String receiverUsername)
			throws HelpRequestException {

		User ureceiver = null;
		if (receiverUsername != null) {
			ureceiver = em.find(User.class, receiverUsername);
		}
		if (ureceiver == null) {
			throw new HelpRequestException();
		}
		Query q = em.createQuery("SELECT object(hr) " 
				+ "FROM HelpRequest hr "
				+ "WHERE  (hr.receiver=:ureceiver AND hr.visibleToReceiver=true) " +
				"ORDER BY hr.date DESC");
		q.setParameter("ureceiver", ureceiver);
		@SuppressWarnings("unchecked")
		Collection<HelpRequest> result = q.getResultList();
		return result;
	}

	
	@Override
	public Collection<HelpRequest> getSentHelpRequest(String senderUsername)
			throws HelpRequestException {

		User usender = null;
		if (senderUsername != null) {
			usender = em.find(User.class, senderUsername);
		}
		if (usender == null) {
			throw new HelpRequestException();
		}
		Query q = em.createQuery("SELECT object(hr) " + "FROM HelpRequest hr "
				+ "WHERE (hr.sender=:usender AND hr.visibleToSender=true) " +
				"ORDER BY hr.date DESC");
		q.setParameter("usender", usender);
		@SuppressWarnings("unchecked")
		Collection<HelpRequest> result = q.getResultList();
		return result;
	}

	
	@Override
	public void acceptHelp(String username, Integer helpId)
			throws HelpRequestException {

		User ureceiver = null;
		HelpRequest hr = null;
		if (username != null && helpId != null) {
			ureceiver = em.find(User.class, username);
			hr = em.find(HelpRequest.class, helpId);
		}
		if (ureceiver == null || hr == null
				|| !responseIsAllowed(ureceiver, hr)) {
			throw new HelpRequestException();
		}

		hr.accept();
		hr.setFeedbackAvailable(true);
		em.flush();
		return;

	}

	
	@Override
	public void refuseHelp(String username, Integer helpId)
			throws HelpRequestException {
		User ureceiver = null;
		HelpRequest hr = null;
		if (username != null && helpId != null) {
			ureceiver = em.find(User.class, username);
			hr = em.find(HelpRequest.class, helpId);
		}
		if (ureceiver == null || hr == null
				|| !responseIsAllowed(ureceiver, hr)) {
			throw new HelpRequestException();
		}

		hr.refuse();
		em.flush();
		return;
	}
	
	
	private boolean responseIsAllowed(User ureceiver, HelpRequest hr) {
		return ureceiver.equals(hr.getReceiver())&&hr.getStatus().equals(RequestStatus.Pending);
	}

	
	@Override
	public void deleteHelp(String username, Integer helpId)
			throws HelpRequestException {

		User usender = null;
		HelpRequest hr = null;
		if (username != null && helpId != null) {
			usender = em.find(User.class, username);
			hr = em.find(HelpRequest.class, helpId);
		}
		if (usender == null || hr == null || !deleteIsAllowed(usender, hr)) {
			throw new HelpRequestException();
		}
		hr.delete();
		em.flush();
		return;

	}

	
	private boolean deleteIsAllowed(User usender, HelpRequest hr) {
		return usender.equals(hr.getSender())&&hr.getStatus().equals(RequestStatus.Pending);
	}

	
	@Override
	public int sendHelpRequest(String sender, String receiver,
			String abilityName, String object) throws HelpRequestException {
		
		User usender = null;
		User ureceiver = null;
		Ability reqAbility = null;
		if (sender != null && receiver != null && abilityName != null) {
			usender = em.find(User.class, sender);
			ureceiver = em.find(User.class, receiver);
			reqAbility = em.find(Ability.class, abilityName);
		}
		if (!parameterAreCorrect(usender, ureceiver, reqAbility, object)) {
			throw new HelpRequestException();
		}
		HelpRequest hr = new HelpRequest(usender, ureceiver, reqAbility, object);
		em.persist(hr);
		return hr.getId();
	}

	
	private boolean parameterAreCorrect(User usender, User ureceiver,
			Ability reqAbility, String object) {
		if (usender == null || ureceiver == null || reqAbility == null
				|| object == null) {
			return false;
		}
		if (!ureceiver.getDeclaredAbilities().contains(reqAbility)) {
			return false;
		}
		return true;
	}

	
	@Override
	public void attachMessage(String senderUsername, Integer helpId,
			String content) throws HelpRequestException {
	
		if(senderUsername==null||helpId==null||content==null){
			throw new HelpRequestException();
		}
		User usender=em.find(User.class, senderUsername);
		HelpRequest hr=em.find(HelpRequest.class, helpId);
		if(usender==null||hr==null||!messagingIsAllowed(usender, hr)){
			throw new HelpRequestException();
		}
		Message message=new Message(usender,content);
		em.persist(message);
		hr.addMessage(message);
		em.flush();
	}

	
	private boolean messagingIsAllowed(User usender, HelpRequest hr) {
		boolean res=hr.getSender().equals(usender)||hr.getReceiver().equals(usender);
		res= res&&hr.getStatus().equals(RequestStatus.Pending);
		return res;
	}
	

	public void removeHelpRequests(Ability a) {
		
		Query q= em.createQuery("SELECT OBJECT(hr) FROM HelpRequest hr WHERE hr.requiredAbility= :ab");
		q.setParameter("ab", a);
		@SuppressWarnings("unchecked")
		List<HelpRequest> result=q.getResultList();
		
		for(HelpRequest hr: result){
			for(Message m: hr.getMessages()){
				em.remove(m);
			}
			em.remove(hr);
		}
	}

	@Override
	public HelpRequest getHelpRequest(Integer id) {
		
		return em.find(HelpRequest.class, id);
	}

 
	@Override
	public void removeHelpRequest(Integer helpId, String username)
			throws HelpRequestException {
		
		HelpRequest hr=em.find(HelpRequest.class, helpId);
		if(hr==null){
			throw new HelpRequestException();
		}
		
		if(hr.getReceiver().getUsername().equals(username)){
			hr.setVisibleToReceiver(false);
		}else if(hr.getSender().getUsername().equals(username)){
			hr.setVisibleToSender(false);
		}else{
			throw new HelpRequestException();
		}
		
		if(!hr.isVisibleToReceiver()&&!hr.isVisibleToSender()){
			em.remove(hr);
		}
		em.flush();
	}
	
	
}
